﻿#include "spellchecker.h"
#include "ui_spellchecker.h"
#include <QFontDatabase>
#include <QClipboard>
#include "document.h"
#include "tools.h"

SpellChecker::SpellChecker (Widget *parent) :
	QDialog (parent),
	ui(new Ui::SpellChecker)
{
	ui->setupUi(this);
	m_progress = new QProgressDialog (tr ("Recherche en cours..."),
									  tr ("&Interrompre"),
									  0,
									  100,
									  this);

	m_progress->setMinimumDuration (30);

	setWindowFlags (Qt::Window
					| Qt::CustomizeWindowHint
					| Qt::WindowTitleHint
					| Qt::WindowMaximizeButtonHint
					| Qt::WindowCloseButtonHint
					| Qt::WindowMinimizeButtonHint);

	setWindowModality (Qt::ApplicationModal);
	m_config = new OrthoConfig (0);
	m_textEdit = ui->textEdit;
	//	ui->textEditLayout->addWidget (m_textEdit);
	m_badIndex = 0;
	m_ortho = new Ortho (this);

	const QStyle* style = qApp->style ();
	ui->save->setIcon (style->standardIcon (QStyle::SP_DialogSaveButton));
	ui->copyToClipboard->setIcon (QIcon::fromTheme ("edit-copy", QIcon (":/images/edit-copy.png")));
	ui->quit->setIcon (style->standardIcon (QStyle::SP_DialogCloseButton));
	setWindowIcon (QIcon::fromTheme ("tools-check-spelling", QIcon (":/images/tools-check-spelling.png")));

	initFontSizeMenu ();

	loadLanguages ();

	connect (m_ortho,
			 SIGNAL(message(QString)),
			 this,
			 SLOT(onMessageFromOrtho(QString)));

	connect (ui->clearMessages,
			 SIGNAL(clicked()),
			 ui->messagesFromOrtho,
			 SLOT(clear()));

	connect (ui->replaceAll,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onReplaceAllClicked()));

	connect (ui->unknownCombo,
			 SIGNAL(currentIndexChanged(QString)),
			 this,
			 SLOT(onUnknownComboIndexChanged(QString)));

	connect (ui->languages,
			 SIGNAL(currentIndexChanged(QString)),
			 this,
			 SLOT(onLanguagesCurrentIndexChange(QString)));

	connect (ui->suggestList,
			 SIGNAL(currentIndexChanged(QString)),
			 this,
			 SLOT(onSuggestListTextChanged(QString)));

	connect (ui->suggestList,
			 SIGNAL(editTextChanged(QString)),
			 this,
			 SLOT(onSuggestListTextChanged(QString)));

	connect (ui->ignore,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onIgnoreClicked ()));

	connect (ui->addToPersonalDic,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onAddToPersonalDicClicked ()));

	connect (ui->runAutoSpelling,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onRunAutoSpellingClicked()));

	connect (ui->cancelAutoSpelling,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onCancelAutoSpellingClicked()));

	connect (m_ortho,
			 SIGNAL(autoSpellingCount(int)),
			 m_progress,
			 SLOT(setMaximum(int)));

	connect (m_ortho,
			 SIGNAL(autoSpellingAdvance(int)),
			 m_progress,
			 SLOT(setValue(int)));

	// options


	connect (ui->tabs,
			 SIGNAL(currentChanged(int)),
			 this,
			 SLOT(onTabsCurrentChanged(int)));

	connect(ui->optionDistanceMax,
			SIGNAL(valueChanged(int)),
			m_config,
			SLOT(setOptionDistanceMax(int)));

	connect(ui->optionLengthMin,
			SIGNAL(valueChanged(int)),
			m_config,
			SLOT(setOptionLengthMin(int)));

	connect(ui->optionWeirdMax,
			SIGNAL(valueChanged(int)),
			m_config,
			SLOT(setOptionWeirdMax(int)));

	connect (ui->removeWordFromText,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onRemoveWordFromTextClicked ()));

	connect (ui->replaceAlways,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onReplaceAlwaysClicked()));

	connect (ui->clearPersonalDic,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onClearPersonalDic()));

	connect (ui->clearTranslateDic,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onClearTranslateDic()));

	connect (m_ortho,
			 SIGNAL(personalDicHasChanged()),
			 this,
			 SLOT(onPersonalDicChange()));

	connect (m_ortho,
			 SIGNAL(translateDicHasChanged()),
			 this,
			 SLOT(onTranslateDicChange()));

	connect (m_progress,
			 SIGNAL(canceled()),
			 m_ortho,
			 SLOT(stopAutoSpelling()));

}
//---------------------------------
void SpellChecker::loadLanguages ()
{
	ui->languages->clear ();
	ui->languages->addItems (m_ortho->availableLanguages ());
	ui->languages->setCurrentIndex (ui->languages->findText (m_ortho->currentLanguage ()));
}
//----------------------------
SpellChecker::~SpellChecker()
{
	delete ui;
	delete m_config;
}
//-----------------------------------------------------------
void SpellChecker::onUnknownComboIndexChanged (QString newWord)
{
//    ui->suggestList->setEditText (newWord);
	ui->suggestList->setFocus ();

	// prévenir qu'on aborde un nouveau mot (le surligner dans l'éditeur)
	m_textEdit->moveCursor (QTextCursor::Start);
	m_textEdit->find (newWord, QTextDocument::FindCaseSensitively | QTextDocument::FindWholeWords);
	m_textEdit->ensureCursorVisible ();

	const QStringList& suggestions (m_ortho->suggestsFor (newWord));
	ui->suggestList->clear ();
	ui->suggestList->addItems (suggestions);
}
//-----------------------------------------
int SpellChecker::run (const QString& text)
{
	setCurrentText (text);
	if (ui->tabs->currentIndex () != 0)
		ui->tabs->setCurrentIndex (0);
	else
		updateDialog ();

	return exec ();
}
//--------------------------------
void SpellChecker::updateDialog ()
{
	QApplication::setOverrideCursor (QCursor(Qt::WaitCursor));
	sendOptionsToOrtho ();
	setCurrentText (m_ortho->translate (currentText ()));
	QStringList badWords (m_ortho->unknownWords (currentText ()));
	ui->unknownCombo->clear ();
	ui->unknownCombo->addItems (badWords);
	ui->unknownCombo->setCurrentIndex (0);
	QString errorText (tr ("%1 erreur%2 détectée%3"));
	const int count = badWords.count ();
	switch (count)
	{
	case 0:
		errorText = errorText.arg ("Aucune").arg ("").arg ("");
		break;

	case 1:
		errorText = errorText.arg ("Une").arg ("").arg ("");
		break;

	default:
		errorText = errorText.arg (count).arg ("s").arg ("s");
		break;
	}

	ui->errorCount->setText (errorText);
	bool test = badWords.isEmpty ();
	ui->removeWordFromText->setDisabled (test);
	ui->ignore->setDisabled (test);
	ui->addToPersonalDic->setDisabled (test);
	ui->runAutoSpelling->setDisabled (test);
	ui->cancelAutoSpelling->setDisabled (m_saveText.isEmpty ());
	ui->save->setDisabled (text ().isEmpty ());
	QApplication::restoreOverrideCursor ();
}
//-----------------------------------------------------------
void SpellChecker::onLanguagesCurrentIndexChange (QString lang)
{
	m_ortho->setCurrentLanguage (lang);
	m_config->setOptionCurrentLanguage (lang);
	updateDialog ();
}
//--------------------------------------------------------
void SpellChecker::onSuggestListTextChanged (QString newWord)
{
	const bool test = newWord.isEmpty () || newWord == ui->unknownCombo->currentText ();
	ui->replaceAll->setDisabled (test);
	ui->replaceAlways->setDisabled (test);
	ui->addToPersonalDic->setDisabled (test);
}
//---------------------------------------
void SpellChecker::onReplaceAllClicked ()
{
	replaceInCurrentText (ui->unknownCombo->currentText (), ui->suggestList->currentText ());
	updateDialog ();
}
//-----------------------------------
void SpellChecker::onIgnoreClicked ()
{
	m_ortho->addToIgnoreList (ui->unknownCombo->currentText ());
	updateDialog ();
}
//---------------------------------------------
void SpellChecker::onAddToPersonalDicClicked ()
{
	m_ortho->addLineToPersonalDic (ui->unknownCombo->currentText ());
	updateDialog ();
}
//-----------------------------------
void SpellChecker::onOptionsDisplay ()
{
	ui->optionDistanceMax->setValue (m_config->optionDistanceMax ());
	ui->optionLengthMin->setValue (m_config->optionLengthMin ());
	ui->optionWeirdMax->setValue (m_config->optionWeirdMax ());
}
//-------------------------------------------------
void SpellChecker::onTabsCurrentChanged (const int index)
{
	switch (index)
	{
	case 0:
		updateDialog ();
		break;

	case 1:
		onOptionsDisplay ();
		break;

	case 2:
		onPersonalDicChange ();
		break;

	case 3:
		onTranslateDicChange ();
		break;

	case 4:
		ui->tabs->setTabIcon (4, QIcon ());


	default:
		break;
	}
}
//--------------------------------------
void SpellChecker::sendOptionsToOrtho ()
{
	m_ortho->setCurrentLanguage (m_config->optionCurrentLanguage ());
	m_ortho->setDistanceMax (m_config->optionDistanceMax ());
	m_ortho->setLengthMin (m_config->optionLengthMin ());
	m_ortho->setWeirdMax (m_config->optionWeirdMax ());
}
//-----------------------------------------------
void SpellChecker::onRemoveWordFromTextClicked ()
{
	replaceInCurrentText (ui->unknownCombo->currentText (), "");
	updateDialog ();
}
//-------------------------------------------------------------------------------
void SpellChecker::replaceInCurrentText (const QString& bad, const QString& good)
{
	QString tmp (currentText ());
	tmp.replace (bad, good);
	setCurrentText (tmp);
}
//-----------------------------------------
void SpellChecker::onReplaceAlwaysClicked()
{
	m_ortho->addLineToTranslateDic (ui->unknownCombo->currentText (), ui->suggestList->currentText ());
	updateDialog ();
}
//-------------------------------------------------
bool SpellChecker::userAgrees (const QString &text)
{
	return QMessageBox::warning (
				this,
				"Ortho",
				text,
				QMessageBox::Ok | QMessageBox::Cancel,
				QMessageBox::Cancel
				) == QMessageBox::Ok;
}
//------------------------------------
void SpellChecker::onClearPersonalDic ()
{
	if (userAgrees (tr ("Cette action va effacer\nvotre dictionnaire personnel")))
	{
		m_ortho->clearPersonalDic ();
	}
}
//--------------------------------------
void SpellChecker::onClearTranslateDic ()
{
	if (userAgrees (tr ("Cette action va effacer\nla liste des remplacements automatiques")))
	{
		m_ortho->clearTranslateDic ();
	}
}
//-------------------------------------------
void SpellChecker::onRunAutoSpellingClicked ()
{
	setDisabled (true);
	m_saveText = text ();
	QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
	setCurrentText (m_ortho->autoSpelling (m_saveText));
	QApplication::restoreOverrideCursor();
	setEnabled (true);
	updateDialog ();
}
//-----------------------------------------------
void SpellChecker::onCancelAutoSpellingClicked ()
{
	setCurrentText (m_saveText);
	m_saveText.clear ();
	updateDialog ();
}
//------------------------------------------------
void SpellChecker::onMessageFromOrtho(QString msg)
{
	ui->tabs->setTabIcon (4, QIcon (":/images/indicator-messages-new.png"));
	ui->messagesFromOrtho->moveCursor (QTextCursor::End);
	ui->messagesFromOrtho->insertHtml (msg);
	ui->messagesFromOrtho->insertPlainText ("\n");
}
//--------------------------------------
void SpellChecker::onPersonalDicChange()
{
	ui->personalDicList->clear ();
	ui->personalDicList->addItems (m_ortho->personalDic ());
	ui->clearPersonalDic->setDisabled (m_ortho->personalDic ().isEmpty ());
	ui->removeLineFromPersonalDic->setDisabled (true);

}
//--------------------------------------------------------------------------------
void SpellChecker::on_personalDicList_currentTextChanged(const QString &currentText)
{
	ui->removeLineFromPersonalDic->setDisabled (currentText.isEmpty ());
}
//-------------------------------------------------------
void SpellChecker::on_removeLineFromPersonalDic_clicked ()
{
	m_ortho->removeLineFromPersonalDic (ui->personalDicList->currentItem ()->text ());
}
//----------------------------------------------------------------------------------
void SpellChecker::on_translateDicList_currentTextChanged(const QString &currentText)
{
	ui->removeLineFromTranslateDic->setDisabled (currentText.isEmpty ());
}
//--------------------------------------
void SpellChecker::onTranslateDicChange ()
{
	ui->translateDicList->clear ();
	ui->translateDicList->addItems (m_ortho->translateDicAsList ());
	ui->clearTranslateDic->setDisabled (m_ortho->translateDicAsList ().isEmpty ());
	ui->removeLineFromTranslateDic->setDisabled (true);
}
//--------------------------------------------------------
void SpellChecker::on_removeLineFromTranslateDic_clicked ()
{
	m_ortho->removeLineFromTranslateDic (ui->translateDicList->currentItem ()->text ());
}
//------------------------------------------------
void SpellChecker::on_mergePersonalDic_clicked ()
{
	QString fileName = QFileDialog::getOpenFileName (
				this,
				tr ("Choisir un dictionnaire à insérer"),
				QDir::homePath (),
				tr ("Textes (*.txt *.dic);;Tous les fichiers (*.*)"),
				0,
				QFileDialog::ReadOnly);

	if (fileName.isEmpty ()) return;

	m_ortho->mergeToPersonalDic (fileName);
}
//------------------------------------------
void SpellChecker::on_analyzeAgain_clicked ()
{
	updateDialog ();
}
//--------------------------------
void SpellChecker::on_save_clicked()
{
	QString fileName = QFileDialog::getSaveFileName  (this,
													  tr ("Enregistrer le texte sous le nom..."),
													  QDesktopServices::storageLocation (QDesktopServices::DocumentsLocation),
													  tr ("Fichiers texte (*.txt)"),
													  0);
	if (fileName.isEmpty ()) return;

	if (!fileName.endsWith (".txt"))
		fileName += ".txt";

	QFile file (fileName);

	if (!file.open (QIODevice::WriteOnly))
	{
		QMessageBox::critical (this,
							   Config::appName (),
							   tr ("Je ne peux pas écrire dans le fichier\n%1").arg (fileName));
		return;
	}

	QByteArray ba;
	ba.append (m_textEdit->toPlainText ());

	file.write (ba);
	file.close ();
}

//-----------------------------------------------------
void SpellChecker::onFontSizeChanged (const QString& size)
{
	int newSize = size.toInt ();
	m_textEdit->selectAll ();
	m_textEdit->setFontPointSize (newSize);
	m_textEdit->moveCursor (QTextCursor::Start);
}
//-------------------------------
void SpellChecker::initFontSizeMenu ()
{
	QString family = qApp->font ().family ();
	QFontDatabase fdb;
	QList<int> sizes (fdb.pointSizes (family));
	if (sizes.isEmpty ())
	{
		sizes = QFontDatabase::standardSizes ();
	}
	ui->fontSize->clear ();
	foreach (int index, sizes)
	{
		ui->fontSize->addItem (QString ("%1").arg (index));
	}
	QString currentSize = QString ("%1").arg (qApp->font().pointSize ());
	ui->fontSize->setCurrentIndex (ui->fontSize->findText (currentSize));
}
//-----------------------------------
void SpellChecker::on_quit_clicked()
{
	accept ();
}
//------------------------------------------------
void SpellChecker::on_copyToClipboard_clicked()
{
	QClipboard* clip = QApplication::clipboard ();
	clip->setText (m_textEdit->toPlainText ());
}
//---------------------------------------------------------------------
void SpellChecker::on_fontSize_currentIndexChanged(const QString &arg1)
{
	int size = arg1.toInt ();
	if (size == 0) size = 10;
	QFont font;
	font.setPointSize (size);
	m_textEdit->setFont (font);
}
